use std::{mem::size_of, os::raw::c_void};

use ash::vk::{self, ImageSubresourceRange};

use crate::{vulkan::{VkContext, vk_struct::{VkImage, VkTexture, VkBuffer, VkMappedBuffer}, vk_utils::{utils_memory::{self, has_stencil_component}, utils_info}}, VK_CHECK, VK_LOGP, VK_CHECK_UNSAFE};

impl VkContext {
    fn get_image_mbarrier(&self, image: &vk::Image) -> vk::ImageMemoryBarrier {
        vk::ImageMemoryBarrier {
            s_type                      : vk::StructureType::IMAGE_MEMORY_BARRIER,
            p_next                      : std::ptr::null(),
            // src_access_mask          : ,
            // dst_access_mask          : ,
            // old_layout               : ,
            // new_layout               : ,
            // src_queue_family_index   : ,
            // dst_queue_family_index   : ,
            image                       : *image,
            // subresource_range        : vk::ImageSubresourceRange

            ..Default::default()
        }
    }

    fn get_image_subsource_range(&self) -> vk::ImageSubresourceRange {
        vk::ImageSubresourceRange {
            aspect_mask             : vk::ImageAspectFlags::COLOR,
            base_mip_level          : 0,
            level_count             : 1,
            base_array_layer        : 0,
            layer_count             : 1
        }
    }

    /// 将old_layout与new_layout两两组合，生成对应的数据
    #[inline]
    fn transition_layout_gen_info(&self, old_layout: &vk::ImageLayout, new_layout: &vk::ImageLayout) 
        -> (vk::PipelineStageFlags, vk::PipelineStageFlags, vk::AccessFlags, vk::AccessFlags) {
        match (*old_layout, *new_layout) {
            // Swapchain出来的Image
            (vk::ImageLayout::UNDEFINED, vk::ImageLayout::PRESENT_SRC_KHR)      
                => (vk::PipelineStageFlags::TOP_OF_PIPE,        vk::PipelineStageFlags::TOP_OF_PIPE,                    vk::AccessFlags::empty(),           vk::AccessFlags::empty()),
            // 读取的Texture，从Buffer转换过来
            (vk::ImageLayout::UNDEFINED, vk::ImageLayout::TRANSFER_DST_OPTIMAL) 
                => (vk::PipelineStageFlags::TOP_OF_PIPE,        vk::PipelineStageFlags::TRANSFER,                       vk::AccessFlags::empty(),           vk::AccessFlags::TRANSFER_WRITE),
            // 手动创建的ColorAttachment
            (vk::ImageLayout::UNDEFINED, vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL)
                => (vk::PipelineStageFlags::TOP_OF_PIPE,        vk::PipelineStageFlags::COLOR_ATTACHMENT_OUTPUT,        vk::AccessFlags::empty(),           vk::AccessFlags::COLOR_ATTACHMENT_READ | vk::AccessFlags::COLOR_ATTACHMENT_WRITE),
            // 手动创建的DepthBuffer
            (vk::ImageLayout::UNDEFINED, vk::ImageLayout::DEPTH_STENCIL_ATTACHMENT_OPTIMAL) 
                => (vk::PipelineStageFlags::TOP_OF_PIPE,        vk::PipelineStageFlags::EARLY_FRAGMENT_TESTS,           vk::AccessFlags::empty(),           vk::AccessFlags::DEPTH_STENCIL_ATTACHMENT_READ | vk::AccessFlags::DEPTH_STENCIL_ATTACHMENT_WRITE),
            
            _ => VK_LOGP!("Wrong Trasision: From {:?} to {:?}", old_layout, new_layout)
        }
    }

    /// 通常我们创建Image还需要放在正确的Layout里面，刚初始化的Image属于UNDEFINED<br>
    /// Image From UNDEFINED代表我们不关心数据来源，也就是不关心数据来的时候是什么<br>
    /// todo 这里的Stage切换和Layout切换会达到什么效果呢？
    pub fn images_transition_layout(&self, images: &[vk::Image], format: &vk::Format, old_layout: vk::ImageLayout, new_layout: vk::ImageLayout) {
        // Start Command
        let command_buffer = self.begin_single_time_commands();

        // Generate more info
        let (src_stage, dst_stage, src_access_mask, dst_access_mask) 
            = self.transition_layout_gen_info(&old_layout, &new_layout);

        let mut image_mbarriers = vec![];

        // Create Image Memory Barriers
        for image in images {
            let mut temp_image_mbarrier = self.get_image_mbarrier(image);
            temp_image_mbarrier.old_layout   = old_layout;
            temp_image_mbarrier.new_layout   = new_layout;
            temp_image_mbarrier.src_access_mask = src_access_mask;
            temp_image_mbarrier.dst_access_mask = dst_access_mask;
            temp_image_mbarrier.subresource_range = self.get_image_subsource_range();

            if new_layout == vk::ImageLayout::DEPTH_STENCIL_ATTACHMENT_OPTIMAL {
                temp_image_mbarrier.subresource_range.aspect_mask = vk::ImageAspectFlags::DEPTH;
                if has_stencil_component(format) { 
                    temp_image_mbarrier.subresource_range.aspect_mask = vk::ImageAspectFlags::STENCIL;
                }
            }

            image_mbarriers.push(temp_image_mbarrier);
        }

        // Add Command
        unsafe{ self.vk_device.cmd_pipeline_barrier(command_buffer, src_stage, dst_stage, vk::DependencyFlags::empty(), &[], &[], &image_mbarriers) };

        self.end_single_time_commands(command_buffer)
    }

    /// 创建ColorBuffer，使用VkImage通用结构
    /// 如果是GBuffer不执行transition
    pub fn create_color_image(&self, width: u32, height: u32, format: vk::Format, is_gbuffer: bool, is_in_pass_texture: bool) -> VkImage {
        let mut usage = vk::ImageUsageFlags::COLOR_ATTACHMENT;
        if is_gbuffer           { usage |= vk::ImageUsageFlags::SAMPLED };              // 如果这里没有SAMPLED, 在管线中无法采样
        if is_in_pass_texture   { usage |= vk::ImageUsageFlags::INPUT_ATTACHMENT };

        let image = VkImage::new(
            &self, 
            width, height, 
            &format, 
            usage,
            &vk::MemoryPropertyFlags::DEVICE_LOCAL,
            vk::ImageAspectFlags::COLOR);
        if !is_gbuffer {
            self.images_transition_layout(&[image.handler], &format, vk::ImageLayout::UNDEFINED, vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL);
        }
        image
    }

    /// 创建ColorBuffer，使用VkTexture通用结构
    pub fn create_color_texture(&self, width: u32, height: u32, format: vk::Format, is_gbuffer: bool, is_in_pass_texture: bool) -> VkTexture {
        let image = self.create_color_image(width, height, format, is_gbuffer, is_in_pass_texture);
        VkTexture::new(&self, &image, if !is_gbuffer { vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL } else { vk::ImageLayout::GENERAL } )
    }

    /// 创建DepthBuffer，使用VkImage通用结构
    pub fn create_depth_image(&self, width: u32, height: u32, format: vk::Format, is_in_pass_texture: bool) -> VkImage {
        let depth_format = utils_memory::find_depth_format(self);
        let mut usage = vk::ImageUsageFlags::DEPTH_STENCIL_ATTACHMENT;
        if is_in_pass_texture { usage |= vk::ImageUsageFlags::INPUT_ATTACHMENT };

        let image = VkImage::new(
            &self, 
            width, height, 
            &depth_format, 
            usage,
            &vk::MemoryPropertyFlags::DEVICE_LOCAL,
            vk::ImageAspectFlags::DEPTH);
        self.images_transition_layout(&[image.handler], &depth_format, vk::ImageLayout::UNDEFINED, vk::ImageLayout::DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
        image
    }

    /// 创建DepthBuffer，使用VkTexture通用结构
    pub fn create_depth_texture(&self, width: u32, height: u32, format: vk::Format, is_in_pass_texture: bool) -> VkTexture {
        let image = self.create_depth_image(width, height, format, is_in_pass_texture);
        VkTexture::new(&self, &image, vk::ImageLayout::DEPTH_STENCIL_ATTACHMENT_OPTIMAL)
    }

    /// 创建Texture的Sampler
    pub fn create_sampler(&self) -> vk::Sampler {
        let sampler_ci = utils_info::get_sampler_create_info();
        match VK_CHECK_UNSAFE!(self.vk_device.create_sampler(&sampler_ci, None)) {
            Some(inner_value)   => inner_value,
            None                => VK_LOGP!("Failed to create_sampler")
        }
    }

    /// 释放资源
    pub fn destory_vk_image(&self, vk_image: &VkImage) {
        vk_image.destory_resources(self);
    }

    /// 释放资源
    pub fn destory_vk_texture(&self, vk_texture: &VkTexture) {
        vk_texture.destory_resources(self);
    }

    /// 释放资源
    pub fn destory_framebuffers(&self, framebuffers: &Vec<vk::Framebuffer>) {
        for framebuffer in framebuffers {
            unsafe{ self.vk_device.destroy_framebuffer(*framebuffer, None); }
        }
    }

    pub fn create_image_view_2d(&self, image: &vk::Image, format: &vk::Format, aspect_mask: &vk::ImageAspectFlags) -> vk::ImageView {
        let mut image_view_ci = utils_info::get_image_view_ci();
        image_view_ci.image                 = *image;
        image_view_ci.view_type             = vk::ImageViewType::TYPE_2D;
        image_view_ci.format                = *format;
        // image_view_ci.components            = ;
        image_view_ci.subresource_range     = vk::ImageSubresourceRange{
            aspect_mask             : *aspect_mask,
            base_mip_level          : 0,
            level_count             : 1,
            base_array_layer        : 0,
            layer_count             : 1
        };

        unsafe {
            self.vk_device
                .create_image_view(&image_view_ci, None)
                .expect("failed to create image view")
        }
    }

    /// 创建Gpu Only Buffer
    /// 使用Stage Buffer进行传输，这样使用起来高效一些
    pub fn create_device_only_buffer(&self, size: u64, usage: vk::BufferUsageFlags, data_to_trans: Option<*const c_void>) -> VkBuffer {
        // 创建用于临时传输的Buffer
        let stage_buffer = VkBuffer::new(self, 
            size, 
            vk::BufferUsageFlags::TRANSFER_SRC, 
            vk::SharingMode::EXCLUSIVE, 
            &(vk::MemoryPropertyFlags::HOST_VISIBLE | vk::MemoryPropertyFlags::HOST_COHERENT), 
            data_to_trans);
        // 创建用于最终放置内容的Buffer
        let device_only_buffer = VkBuffer::new(self, 
            size, 
            vk::BufferUsageFlags::TRANSFER_DST | usage, 
            vk::SharingMode::EXCLUSIVE, 
            &vk::MemoryPropertyFlags::DEVICE_LOCAL, 
            None);
        // 将Stage Buffer里面存的内容通过Cmd进行Device to Device的内存传输
        self.copy_buffer(&stage_buffer, &device_only_buffer, vec![vk::BufferCopy {size: size, ..Default::default()}]);
        // 理论上这里需要Release，但是不知道是不是会自动清除
        // stage_buffer.release();

        device_only_buffer
    }

    pub fn create_uniform_buffer<T>(&self) -> VkMappedBuffer<T> {
        VkMappedBuffer::new(self, 
            size_of::<T>() as u64, 
            vk::BufferUsageFlags::UNIFORM_BUFFER,
            vk::SharingMode::EXCLUSIVE, 
            &(vk::MemoryPropertyFlags::HOST_VISIBLE | vk::MemoryPropertyFlags::HOST_COHERENT), 
            None
        )
    }

    /// 创建Uniform Buffers
    pub fn create_uniform_buffers<T>(&self, buffer_count: usize) -> Vec<VkMappedBuffer<T>> {
        let mut uniform_buffers = vec![];
        
        for _ in 0..buffer_count {
            uniform_buffers.push(self.create_uniform_buffer())
        }

        uniform_buffers
    }

    /// 拷贝内存操作
    /// 多用于Stage Buffer进行传输
    pub fn copy_buffer(&self, src_buffer: &VkBuffer, dst_buffer: &VkBuffer, copy_rule: Vec<vk::BufferCopy>) {
        let signle_command_buffer = self.begin_single_time_commands();
        unsafe{ self.vk_device.cmd_copy_buffer(signle_command_buffer, src_buffer.handler, dst_buffer.handler, &copy_rule) }
        self.end_single_time_commands(signle_command_buffer);
    }
}